//
//  neuralnetwork.h
//  neuralnetwork
//
//  Created by tianshuai on 7/13/15.
//

#ifndef NEURALNETWORK_H
#define NEURALNETWORK_H

#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <vector>

typedef std::vector<double> Value;
typedef std::vector<int> Topology;

/* links between nodes */
struct Link
{
    double weight;
    double DerivWeight;
};

typedef std::vector<Link> Links;

class Node
{
public:
    Node(int OutCount, int idx);
    
    void setOut(double val){ OutValue = val; }
    double getOutValue() const { return OutValue; }
    
    void FeedFwd(const std::vector<Node>& level);
    
    void calcOutGradients(double GoalValue);
    void calcHiddenGradients(const std::vector<Node>& nextLevel);
    
    void updateInWeights(std::vector<Node>& level);
    
private:
    double sumDerivWeights(const std::vector<Node>& nextLevel) const;
    
    static double rand0to1() { return rand()/float(RAND_MAX); }/* selects random value between 0 and 1 */
    static double TransFunc(double in)
    {
        return std::tanh(in);
    }
    static double TransFuncDer(double in)
    {
        double x = in;
        return 1.0 - in * in; /* 1-tanh^2 */
    }
    
    double OutValue;
    int index;
    Links OutWeights;
    double gradient;
    
    static float alpha;  /* momentum */
    static float eta;    /* learning rate */
};
/* Row of Nodes */
typedef std::vector<Node> Level;

class NeuralNetwork
{
public:
    NeuralNetwork(const Topology& Topol);
    void train(Value&& In, Value&& Goal);
    Value run(Value&& In);
    
    /* 前馈网络 */
    void FeedForward(const Value& In);
    /* 反馈网络 */
    void BackPropagation(const Value& Goal);
    void getOutput(Value& results) const;
    
private:
    typedef std::vector<Level> Levels;
    Levels levels;
    
    double error;
    /*displays error from goal*/
    double DisplayError;
    double DisplaySmoothingFactor;
};

#endif
